package com.qolome.knowledge.features.player.music;

import javazoom.spi.mpeg.sampled.file.MpegAudioFileReader;
import org.jaudiotagger.audio.exceptions.InvalidAudioFrameException;
import org.jaudiotagger.audio.exceptions.ReadOnlyFileException;
import org.jaudiotagger.audio.mp3.MP3File;
import org.jaudiotagger.tag.TagException;
import org.jaudiotagger.tag.id3.AbstractID3v2Frame;
import org.jaudiotagger.tag.id3.AbstractID3v2Tag;
import org.jaudiotagger.tag.id3.framebody.FrameBodyAPIC;

import javax.sound.sampled.*;
import javax.swing.*;
import java.awt.*;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * @author Qolome
 * @version V1.0
 * @Description 音乐播放
 * @date 2020年 02月26日 13:45:34
 */
public class MusicPlayer implements IMusicPlayer {


    @Override
    public void flac(String path) throws UnsupportedAudioFileException, IOException {
        File file = new File(path);
        if (!file.exists() || !path.toLowerCase().endsWith(".flac")) {
            return;
        }
        AudioInputStream audio = AudioSystem.getAudioInputStream(file);
        AudioFormat format = audio.getFormat();
        if (format.getEncoding() != AudioFormat.Encoding.PCM_SIGNED) {
            format = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, format.getSampleRate(), 16, format.getChannels(), format.getChannels() * 2, format.getSampleRate(), false);
            audio = AudioSystem.getAudioInputStream(format, audio);
        }
        DataLine.Info info = new DataLine.Info(SourceDataLine.class, format, AudioSystem.NOT_SPECIFIED);
        SourceDataLine data = null;
        try {
            data = (SourceDataLine) AudioSystem.getLine(info);
            data.open(format);
            data.start();
            byte[] bt = new byte[1024];
            while (audio.read(bt) != -1) {
                data.write(bt, 0, bt.length);
            }
            data.drain();
            data.stop();
            data.close();
            audio.close();
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
    }

    @Override
    public void wav(String path) throws UnsupportedAudioFileException, IOException {
        File file = new File(path);
        if (!file.exists() || !path.toLowerCase().endsWith(".wav")) {
            throw new RuntimeException("文件不存在");
        }
        AudioInputStream stream = AudioSystem.getAudioInputStream(file);
        AudioFormat target = stream.getFormat();
        DataLine.Info dinfo = new DataLine.Info(SourceDataLine.class, target);
        SourceDataLine line = null;
        int len = -1;
        try {
            line = (SourceDataLine) AudioSystem.getLine(dinfo);
            line.open(target);
            line.start();
            byte[] buffer = new byte[1024];
            while ((len = stream.read(buffer)) > 0) {
                line.write(buffer, 0, len);
            }
            line.drain();
            line.stop();
            line.close();
            stream.close();
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
    }

    @Override
    public void pcm(String path) throws UnsupportedAudioFileException, IOException {
        File file = new File(path);
        if (!file.exists() || !path.toLowerCase().endsWith(".pcm")) {
            throw new RuntimeException("文件不存在");
        }
        AudioInputStream stream = AudioSystem.getAudioInputStream(file);
        AudioFormat target = stream.getFormat();
        DataLine.Info dinfo = new DataLine.Info(SourceDataLine.class, target, AudioSystem.NOT_SPECIFIED);
        SourceDataLine line = null;
        int len = -1;
        try {
            line = (SourceDataLine) AudioSystem.getLine(dinfo);
            line.open(target);
            line.start();
            byte[] buffer = new byte[1024];
            while ((len = stream.read(buffer)) > 0) {
                line.write(buffer, 0, len);
            }
            line.drain();
            line.stop();
            line.close();
            stream.close();
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
    }

    @Override
    public void mp3(String path) throws UnsupportedAudioFileException, IOException {
        File file = new File(path);
        if (!file.exists() || !path.toLowerCase().endsWith(".mp3")) {
            throw new RuntimeException("文件不存在");
        }
        AudioInputStream stream = null;
        //使用 mp3spi 解码 mp3 音频文件
        MpegAudioFileReader mp = new MpegAudioFileReader();
        stream = mp.getAudioInputStream(file);
        AudioFormat baseFormat = stream.getFormat();
        //设定输出格式为pcm格式的音频文件
        AudioFormat format = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, baseFormat.getSampleRate(), 16, baseFormat.getChannels(), baseFormat.getChannels() * 2, baseFormat.getSampleRate(), false);
        // 输出到音频
        stream = AudioSystem.getAudioInputStream(format, stream);
        AudioFormat target = stream.getFormat();
        DataLine.Info dinfo = new DataLine.Info(SourceDataLine.class, target, AudioSystem.NOT_SPECIFIED);
        SourceDataLine line = null;
        int len = -1;
        try {
            line = (SourceDataLine) AudioSystem.getLine(dinfo);
            line.open(target);
            line.start();
            byte[] buffer = new byte[1024];
            while ((len = stream.read(buffer)) > 0) {
                line.write(buffer, 0, len);
            }
            line.drain();
            line.stop();
            line.close();
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        } finally {
            stream.close();
        }
    }

    @Override
    public AudioInputStream readPcm(String path) throws UnsupportedAudioFileException, IOException {
        File file = new File(path);
        if (!file.exists()) {
            return null;
        }
        AudioInputStream stream = AudioSystem.getAudioInputStream(file);
        AudioFormat format = stream.getFormat();
        System.out.println(format.toString());
        return stream;
    }


    @Override
    public void wavToPcm(String wpath, String ppath) {
        File file = new File(wpath);
        if (!file.exists()) {
            throw new RuntimeException("文件不存在");
        }
        AudioInputStream stream1;
        try {
            stream1 = AudioSystem.getAudioInputStream(file);
            // 根据实际情况修改 AudioFormat.Encoding.PCM_SIGNED
            AudioInputStream stream2 = AudioSystem.getAudioInputStream(AudioFormat.Encoding.PCM_SIGNED, stream1);
            AudioSystem.write(stream2, AudioFileFormat.Type.WAVE, new File(ppath));
            stream2.close();
            stream1.close();
        } catch (UnsupportedAudioFileException | IOException e) {
            throw new RuntimeException(e.getMessage());
        }
    }


    @Override
    public String getInfo(String path) {
        File file = new File(path);
        AudioInputStream ais;
        String result = "";
        try {
            ais = AudioSystem.getAudioInputStream(file);
            AudioFormat af = ais.getFormat();
            result = af.toString();
            System.out.println(result);
            System.out.println("音频总帧数：" + ais.getFrameLength());
            System.out.println("每秒播放帧数：" + af.getSampleRate());
            float len = ais.getFrameLength() / af.getSampleRate();
            System.out.println("音频时长（秒）：" + len);
            System.out.println("音频时长：" + (int) len / 60 + "分" + len % 60 + "秒");
        } catch (UnsupportedAudioFileException e) {
            throw new RuntimeException(e.getMessage());
        } catch (IOException e) {
            throw new RuntimeException(e.getMessage());
        }
        return result;
    }

    @Override
    public void getImageFromMp3(String mp3Path, String savePath) throws IOException, TagException, ReadOnlyFileException, InvalidAudioFrameException {
        File sourceFile = new File(mp3Path);
        MP3File mp3file = new MP3File(sourceFile);
        AbstractID3v2Tag tag = mp3file.getID3v2Tag();
        AbstractID3v2Frame frame = (AbstractID3v2Frame) tag.getFrame("APIC");
        FrameBodyAPIC body = (FrameBodyAPIC) frame.getBody();
        byte[] image = body.getImageData();
        Image img = Toolkit.getDefaultToolkit().createImage(image, 0, image.length);
        ImageIcon icon = new ImageIcon(img);
        FileOutputStream fos = new FileOutputStream(savePath);
        fos.write(image);
        fos.close();
        System.out.println("width:" + icon.getIconWidth());
        System.out.println("height:" + icon.getIconHeight());
    }

}
